package controller;

import controller.util.JsfUtil;
import facade.*;
import java.io.Serializable;
import java.util.*;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.faces.event.ActionEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;
import modelo.*;

@ManagedBean(name = "contratoController")
@SessionScoped
public class ContratoController implements Serializable {

    private Contrato current;
    private Matricula currentMatricula;
    private CondicoesContrato currentCondicoesContrato;
    private Baixas currentBaixas;
    
    private DataModel items = null;
    private DataModel itemsMatricula = null;
    private DataModel itemsCondicoesContrato = null;
    
    private List<Matricula> listMatriculaAUX;
    private List<CondicoesContrato> listCondicoesContratoAUX;
    
    @EJB
    private facade.ContratoFacade ejbFacade;
    @EJB
    private facade.MatriculaFacade ejbMatriculaFacade;
    @EJB
    private facade.ProdutoFacade ejbProdutoFacade;
    @EJB
    private facade.CondicoesContratoFacade ejbCondicoesContratoFacade;
    @EJB
    private facade.TituloFacade ejbTituloFacade;
    @EJB
    private facade.TituloReceberFacade ejbTituloReceberFacade;
    @EJB
    private facade.BaixasFacade ejbBaixasFacade;
    
    private double valorTotalContrato = 0;
    private double valorTotalCondicoesContrato = 0;
    
    private boolean renderizaMatricula = false;
    private boolean renderizaCondicoesContrato = false;
    private boolean renderizaBotaoSalvar = false;
    private boolean renderizaEdicaoContrato = false;
    
    private Calendar calDataIni = Calendar.getInstance();

    public ContratoController() {
    }

    public Contrato getSelected() {
        if (current == null) {
            current = new Contrato();
        }
        return current;
    }

    public Matricula getMatriculaSelected() {
        if (currentMatricula == null) {
            currentMatricula = new Matricula();
        }
        return currentMatricula;
    }

    public CondicoesContrato getCondicoesContratoSelected() {
        if (currentCondicoesContrato == null) {
            currentCondicoesContrato = new CondicoesContrato();
        }
        return currentCondicoesContrato;
    }

    public Baixas getBaixasSelected() {
        if (currentBaixas == null) {
            currentBaixas = new Baixas();
        }
        return currentBaixas;
    }

    private ContratoFacade getFacade() {
        return ejbFacade;
    }

    private MatriculaFacade getMatriculaFacade() {
        return ejbMatriculaFacade;
    }

    private ProdutoFacade getProdutoFacade() {
        return ejbProdutoFacade;
    }

    private CondicoesContratoFacade getCondicoesContratoFacade() {
        return ejbCondicoesContratoFacade;
    }

    private TituloFacade getTituloFacade() {
        return ejbTituloFacade;
    }

    private TituloReceberFacade getTituloReceberFacade() {
        return ejbTituloReceberFacade;
    }

    private BaixasFacade getBaixasFacade() {
        return ejbBaixasFacade;
    }

    public String prepareList() {
        recreateModel();
        recreateModelMatricula();
        recreateModelCondicoesContrato();
        return "List";
    }

    public String prepareView() {
        setRenderizaMatricula(true);
        current = (Contrato) getItems().getRowData();
        recreateModelMatricula();
        listMatriculaAUX = getMatriculaFacade().findByContrato(current);
        recreateModelCondicoesContrato();
        listCondicoesContratoAUX = getCondicoesContratoFacade().findByContrato(current);
        return "View";
    }

    public String prepareCreate() {
        setRenderizaMatricula(false);
        current = new Contrato();
        recreateModelMatricula();
        listMatriculaAUX = new ArrayList<Matricula>();
        recreateModelCondicoesContrato();
        listCondicoesContratoAUX = new ArrayList<CondicoesContrato>();
        return "Create";
    }

    public void prepareCreateMatricula(ActionEvent actionEvent) {
        currentMatricula = new Matricula();
    }

    public void prepareCreateCondicoesContrato(ActionEvent actionEvent) {
        currentCondicoesContrato = new CondicoesContrato();
    }

    public String create() {
        try {
            getFacade().create(current);

            for (Matricula m : listMatriculaAUX) {
                m.setContrato(current);
                getMatriculaFacade().create(m);
            }

            for (CondicoesContrato c : listCondicoesContratoAUX) {

                c.setContrato(current);
                getCondicoesContratoFacade().create(c);

                int i = 0;
                int idTitulo = (getTituloFacade().getMaxIdTitulo() + 1);
                int parcela = 1;
                double valor = c.getValor() / c.getCondicaoPagamento().getVezes();

                //pegando data atual
                Calendar dataBase = Calendar.getInstance();
                dataBase.setTime(new Date());

                c.setTituloReceberList(new ArrayList<TituloReceber>());

                //loop de geracao de titulos
                while (i < c.getCondicaoPagamento().getVezes()) {

                    //somando um mes
                    if (i > 0 || !c.getCondicaoPagamento().isEntrada()) {
                        dataBase.add(Calendar.MONTH, 1);
                    }

                    //gerando titulos
                    TituloReceber tituloReceber =
                            new TituloReceber(idTitulo, parcela, new Date(), dataBase.getTime(), valor, c);
                    getTituloFacade().create(tituloReceber);
                    if (c.getCondicaoPagamento().isEntrada() && i == 0) {
                        getBaixasFacade().create(new Baixas(dataBase.getTime(), valor, tituloReceber));
                    }
                    i++;
                    parcela++;
                }

            }

            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("ContratoCreated"));
            recreateModel();
            recreateModelMatricula();
            return prepareList();
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public void createMatricula(ActionEvent actionEvent) {
        
        listMatriculaAUX.add(currentMatricula);
        itemsMatricula = new ListDataModel(listMatriculaAUX);
        JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("MatriculaCreated"));

    }

    public void createCondicoesContrato(ActionEvent actionEvent) {

        listCondicoesContratoAUX.add(currentCondicoesContrato);
        itemsCondicoesContrato = new ListDataModel(listCondicoesContratoAUX);
        JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("CondicoesContratoCreated"));

    }

    public String prepareEdit() {
        current = (Contrato) getItems().getRowData();
        recreateModelMatricula();
        listMatriculaAUX = getMatriculaFacade().findByContrato(current);
        recreateModelCondicoesContrato();
        listCondicoesContratoAUX = getCondicoesContratoFacade().findByContrato(current);
        return "Edit";
    }

    public void prepareEditMatricula(ActionEvent actionEvent) {
        currentMatricula = (Matricula) getItemsMatricula().getRowData();
    }

    public void prepareEditCondicoesContrato(ActionEvent actionEvent) {
        currentCondicoesContrato = (CondicoesContrato) getItemsCondicoesContrato().getRowData();
    }

    public String update() {
        try {
            
            //atualizando novas quantidades
            for (Matricula m : listMatriculaAUX) {
                m.setContrato(current);
            }

            for (CondicoesContrato c : listCondicoesContratoAUX) {

                c.setContrato(current);

                int i = 0;
                int idTitulo = getTituloFacade().getMaxIdTitulo();
                int parcela = 1;
                double valor = (c.getValor() / c.getCondicaoPagamento().getVezes());

                //pegando data atual
                Calendar dataBase = Calendar.getInstance();
                dataBase.setTime(new Date());

                //loop de geracao de titulos
                while (i < currentCondicoesContrato.getCondicaoPagamento().getVezes()) {

                    //somando um mes
                    dataBase.add(Calendar.MONTH, 1);

                    //gerando titulos
                    TituloReceber tituloReceber =
                            new TituloReceber(idTitulo, parcela, new Date(), dataBase.getTime(), valor, currentCondicoesContrato);
                    c.getTituloReceberList().add(tituloReceber);
                    i++;
                    parcela++;
                }

            }

            current.setMatriculaList(listMatriculaAUX);
            current.setCondicoesContratoList(listCondicoesContratoAUX);

            getFacade().edit(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("ContratoUpdated"));
            return prepareList();
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public void updateMatricula(ActionEvent actionEvent) {
        try {
            listMatriculaAUX.set(listMatriculaAUX.indexOf(currentMatricula), currentMatricula);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("MatriculaUpdated"));
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
        }
    }

    public void updateCondicoesContrato(ActionEvent actionEvent) {
        try {
            listCondicoesContratoAUX.set(listCondicoesContratoAUX.indexOf(currentCondicoesContrato), currentCondicoesContrato);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("CondicoesContratoUpdated"));
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
        }
    }

    public String destroy() {
        current = (Contrato) getItems().getRowData();
        current.setMatriculaList(listMatriculaAUX);
        current.setCondicoesContratoList(listCondicoesContratoAUX);

        performDestroy();
        recreateModel();
        return "List";
    }

    public void destroyMatricula(ActionEvent actionEvent) {
        currentMatricula = (Matricula) getItemsMatricula().getRowData();
        performDestroyMatricula();
        recreateModelMatricula();
    }

    public void destroyCondicoesContrato(ActionEvent actionEvent) {
        currentCondicoesContrato = (CondicoesContrato) getItemsCondicoesContrato().getRowData();
        performDestroyCondicoesContrato();
        recreateModelCondicoesContrato();
    }

    private void performDestroy() {
        try {
            getFacade().remove(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("ContratoDeleted"));
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
        }
    }

    private void performDestroyMatricula() {
        listMatriculaAUX.remove(currentMatricula);
    }

    private void performDestroyCondicoesContrato() {
        listCondicoesContratoAUX.remove(currentCondicoesContrato);
    }

    public DataModel getItems() {
        if (items == null) {
            items = new ListDataModel(getFacade().findAll());
        }
        return items;
    }

    public DataModel getItemsMatricula() {
        if (itemsMatricula == null) {
            if (current.getIdContrato() != null) {
                itemsMatricula = new ListDataModel(listMatriculaAUX);
            } else {
                itemsMatricula = new ListDataModel();
            }
        }
        return itemsMatricula;
    }

    public DataModel getItemsCondicoesContrato() {
        if (itemsCondicoesContrato == null) {
            if (current.getIdContrato() != null) {
                itemsCondicoesContrato = new ListDataModel(listCondicoesContratoAUX);
            } else {
                itemsCondicoesContrato = new ListDataModel();
            }
        }
        return itemsCondicoesContrato;
    }

    private void recreateModel() {
        items = null;
    }

    private void recreateModelMatricula() {
        itemsMatricula = null;
    }

    private void recreateModelCondicoesContrato() {
        itemsCondicoesContrato = null;
    }

    public SelectItem[] getItemsAvailableSelectMany() {
        return JsfUtil.getSelectItems(ejbFacade.findAll(), false);
    }

    public SelectItem[] getItemsAvailableSelectOne() {
        return JsfUtil.getSelectItems(ejbFacade.findAll(), true);
    }

    public double getValorTotalContrato() {
        double valorDesconto = 0;
        valorTotalContrato = 0;
        for (Matricula m : listMatriculaAUX) {
            valorTotalContrato += m.getValorTotal();
        }
        if (current.getPerDesconto() > 0){
            valorDesconto = valorTotalContrato * (current.getPerDesconto()/100);
        }
        return valorTotalContrato -= valorDesconto;
    }

    public double getValorTotalCondicoesContrato() {
        valorTotalCondicoesContrato = 0;
        for (CondicoesContrato c : listCondicoesContratoAUX) {
            valorTotalCondicoesContrato += (c.getValor());
        }
        return valorTotalCondicoesContrato;
    }
    
    public void gatilhaDataIni(){
        
        calDataIni.setTime(currentMatricula.getDataInicio());
    }
    
    public void gatilhaDataFim(){
        
        Calendar calDataFim = Calendar.getInstance();
        
        calDataFim.setTime(calDataIni.getTime());
        calDataFim.add(Calendar.MONTH,currentMatricula.getMeses());
        
        currentMatricula.setDataFim(calDataFim.getTime());
    }

    protected UIComponent findComponent(UIComponent parent, String id) {
        if (id == null) {
            return null;
        }

        if (id.equals(parent.getId())) {
            return parent;
        }

        Iterator<UIComponent> kids = parent.getFacetsAndChildren();
        while (kids.hasNext()) {
            UIComponent kid = kids.next();
            UIComponent found = findComponent(kid, id);
            if (found != null) {
                return found;
            }
        }
        return null;
    }

    public boolean isRenderizaMatricula() {
        return renderizaMatricula;
    }

    public void setRenderizaMatricula(boolean renderizaMatricula) {
        this.renderizaMatricula = renderizaMatricula;
    }

    public boolean isRenderizaCondicoesContrato() {
        return renderizaCondicoesContrato;
    }

    public void setRenderizaCondicoesContrato(boolean renderizaCondicoesContrato) {
        this.renderizaCondicoesContrato = renderizaCondicoesContrato;
    }

    public void mostrarMatricula() {
        setRenderizaMatricula(true);
    }

    public void mostrarCondicoesContrato() {
        setRenderizaCondicoesContrato(true);
    }

    public boolean isRenderizaBotaoSalvar() {
        renderizaBotaoSalvar = ((getValorTotalContrato() == getValorTotalCondicoesContrato())
                && (getValorTotalContrato() > 0));
        return renderizaBotaoSalvar;
    }
    
    public boolean isRenderizaEdicaoContrato() {
        renderizaEdicaoContrato = false;
        if (getCondicoesContratoFacade().findByContrato(current) == null){
            renderizaEdicaoContrato = true;
        }
        return renderizaEdicaoContrato;
    }

    @FacesConverter(forClass = Contrato.class)
    public static class ContratoControllerConverter implements Converter {

        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            ContratoController controller = (ContratoController) facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "contratoController");
            return controller.ejbFacade.find(getKey(value));
        }

        java.lang.Integer getKey(String value) {
            java.lang.Integer key;
            key = Integer.valueOf(value);
            return key;
        }

        String getStringKey(java.lang.Integer value) {
            StringBuffer sb = new StringBuffer();
            sb.append(value);
            return sb.toString();
        }

        public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof Contrato) {
                Contrato o = (Contrato) object;
                return getStringKey(o.getIdContrato());
            } else {
                throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + ContratoController.class.getName());
            }
        }
    }
}